package hhm.wcnmd.core;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.apache.commons.net.telnet.TelnetClient;

import hhm.wcnmd.core.exection.TimeoutExecution;
import hhm.wcnmd.core.model.CmdResponse;
import hhm.wcnmd.core.model.ConnInfoBean;
import hhm.wcnmd.core.model.ConnectResponse;
import hhm.wcnmd.core.utils.CmdStringUtils;

public class TelNetInstance {
	private static final String TERM_TYPE = "VT220";
	private TelnetClient client = new TelnetClient(TERM_TYPE);
	private static final String DEST_CHARSET = "GBK";
	public volatile static TelNetInstance uniqueInstance = null;
	private InputStream input;
	private OutputStream output;
	private Set<ConnInfoBean> connInfoSet = new HashSet<ConnInfoBean>();
	private String execResult = "";
	private String execCmd = "";
	private static List<String> endPromptSet = new ArrayList<String>();

	static {
		endPromptSet.add("-- more --, next page: Space, continue: g, quit: ^C");
		endPromptSet.add("sername:");
		endPromptSet.add("assword:");
		endPromptSet.add("ogin:");

	}

	public void disconnect() {
		try {
			client.disconnect();
			connInfoSet.clear();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public ConnectResponse connect(String host, int port, String username, String password, ConnectResponse response) {
		execResult = "";
		ConnInfoBean connInfoBean = new ConnInfoBean(host, port);
		if (connInfoSet.contains(connInfoBean)) {
			response.setSuccess(false).setMsg("连接错误,已经存在该连接实例");
			return response;
		}

		try {
			client.connect(host, port);

			input = client.getInputStream();
			output = client.getOutputStream();
			String loginOutput = readTo();
			output.write((username + "\r\n").getBytes());
			output.flush();
			String passwordOutput = readTo();
			output.write((password + "\r\n").getBytes());
			output.flush();
			String promptOutput = readTo();
			execResult = loginOutput + passwordOutput + password + promptOutput;
			response.setSuccess(true).setMsg("连接成功").setData(execResult);

			// 连接成功后，要根据返回的结果，判断prompt
			response.setPrompt(CmdStringUtils.getPrompt(execResult));

			connInfoSet.add(connInfoBean);
		} catch (IOException e) {
			response.setSuccess(false).setMsg("连接错误,请确认认证信息是否有效");
			e.printStackTrace();
		}
		return response;
	}

	public static TelNetInstance getInstance() {
		if (uniqueInstance == null) {
			synchronized (TelNetInstance.class) {
				if (uniqueInstance == null) {
					uniqueInstance = new TelNetInstance();
				}
			}
		}
		return uniqueInstance;
	}

	private String readTo(String... end) {

		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		final byte[] buf = new byte[10240];
		try {
			while (true) {
				int read;
				TimeoutExecution<Integer> timeoutExecution = new TimeoutExecution<Integer>() {
					@Override
					protected Integer execute() throws Exception {
						return input.read(buf);
					}
				};
				if (timeoutExecution.execute(1, TimeUnit.SECONDS)) {
					read = timeoutExecution.getResult(); // 没有超时获得读取的数据长
				} else {
					// 超时
					break;
				}
				if (read != -1) { // 读到数据
					outputStream.write(buf, 0, read);

					if (endPromptSet.contains(outputStream.toString(DEST_CHARSET))) {
						break;

					}

				}

			}
			outputStream.close();
			// 将换行符统一为windows的换行符
			return outputStream.toString(DEST_CHARSET).replaceAll(Constants.LINE_BREAK_LINUX,
					Constants.LINE_BREAK_WINDOWS);
		} catch (IOException e) {
			e.printStackTrace();
			return "";
		}
	}

	public TelNetInstance sendCommand() throws IOException {

		execResult = "";
		output.write(execCmd.getBytes());

		if (!execCmd.equals(Constants.KEY_SPACE)) {
			output.write('\r');
			output.write('\n');
		}
		output.flush();
		execResult = readTo();

		return this;
	}

	public String toExecResult() {
		return execResult;
	}

	public TelNetInstance setExecCmd(String execCmd) {
		this.execCmd = execCmd;
		return this;
	}

	public void handleResult(CmdResponse response) {

		// 清除开头重复的字符
		execResult = CmdStringUtils.clearHeaderCmdStr(execResult, execCmd);

		response.setData(execResult).setSuccess(true);

	}

}
